/*********************************************************
 *
 * MDCM
 *
 * Modifications github.com/issakomi
 *
 *********************************************************/

/*=========================================================================

  Program: GDCM (Grassroots DICOM). A DICOM library

  Copyright (c) 2006-2011 Mathieu Malaterre
  All rights reserved.
  See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "mdcmSorter.h"
#include "mdcmElement.h"
#include "mdcmFile.h"
#include "mdcmReader.h"
#include <algorithm>

namespace mdcm
{

Sorter::Sorter()
{
  SortFunc = NULL;
  TagsToRead = std::set<Tag>();
}

Sorter::~Sorter()
{
}

void Sorter::SetTagsToRead(std::set<Tag> const & tags)
{
  TagsToRead = tags;
}

void Sorter::SetSortFunction(SortFunction f)
{
  SortFunc = f;
}


namespace
{

class SortFunctor
{
public:
  bool operator() (File const *file1, File const *file2)
  {
    return (SortFunc)(file1->GetDataSet(), file2->GetDataSet());
  }
  Sorter::SortFunction SortFunc;
  SortFunctor()
  {
    SortFunc = 0;
  }
  SortFunctor(SortFunctor const &sf)
  {
    SortFunc = sf.SortFunc;
  }
  void operator=(Sorter::SortFunction sf)
  {
    SortFunc = sf;
  }
};

}

bool Sorter::StableSort(std::vector<std::string> const & filenames)
{
  // Can not clear Filenames since input filenames could also be the output
  if(filenames.empty() || !SortFunc)
  {
    Filenames.clear();
    return true;
  }

  std::vector< SmartPointer<FileWithName> > filelist;
  filelist.resize(filenames.size());

  std::vector< SmartPointer<FileWithName> >::iterator it2 = filelist.begin();
  for(std::vector<std::string>::const_iterator it = filenames.begin();
    it != filenames.end() && it2 != filelist.end(); ++it, ++it2)
  {
    Reader reader;
    reader.SetFileName(it->c_str());
    SmartPointer<FileWithName> &f = *it2;

    bool readWasSuccessful = TagsToRead.empty() ? reader.Read() : reader.ReadSelectedTags(TagsToRead);
    if (readWasSuccessful)
    {
      f = new FileWithName(reader.GetFile());
      f->filename = *it;
    }
    else
    {
      mdcmErrorMacro("Could not read: " << it->c_str());
      return false;
    }
  }
  SortFunctor sf;
  sf = Sorter::SortFunc;
  std::stable_sort(filelist.begin(), filelist.end(), sf);

  Filenames.clear();
  for(it2 = filelist.begin(); it2 != filelist.end(); ++it2)
  {
    SmartPointer<FileWithName> const & f = *it2;
    Filenames.push_back(f->filename);
  }

  return true;
}

bool Sorter::Sort(std::vector<std::string> const & filenames)
{
  Filenames.clear();

  if(filenames.empty() || !SortFunc) return true;

  std::vector< SmartPointer<FileWithName> > filelist;
  filelist.resize(filenames.size());

  std::vector< SmartPointer<FileWithName> >::iterator it2 = filelist.begin();
  for(std::vector<std::string>::const_iterator it = filenames.begin();
    it != filenames.end() && it2 != filelist.end(); ++it, ++it2)
  {
    Reader reader;
    reader.SetFileName(it->c_str());
    SmartPointer<FileWithName> &f = *it2;
    bool readWasSuccessful = TagsToRead.empty() ? reader.Read() : reader.ReadSelectedTags(TagsToRead);
    if (readWasSuccessful)
    {
      f = new FileWithName(reader.GetFile());
      f->filename = *it;
    }
    else
    {
      mdcmErrorMacro("File could not be read: " << it->c_str());
      return false;
    }
  }
  SortFunctor sf;
  sf = Sorter::SortFunc;
  std::sort(filelist.begin(), filelist.end(), sf);

  for(it2 = filelist.begin(); it2 != filelist.end(); ++it2)
  {
    SmartPointer<FileWithName> const & f = *it2;
    Filenames.push_back(f->filename);
  }

  return true;
}

bool Sorter::AddSelect(Tag const &tag, const char *value)
{
  Selection.insert(SelectionMap::value_type(tag,value));
  return true;
}


void Sorter::Print(std::ostream &os) const
{
  std::vector<std::string>::const_iterator it = Filenames.begin();
  for(; it != Filenames.end(); ++it)
  {
    os << *it <<std::endl;
  }
}

} // end namespace mdcm
